package com.wechat.back.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wechat.back.mapper.LikeMapper;
import com.wechat.back.mapper.PlaceMapper;
import com.wechat.back.mapper.UserMapper;
import com.wechat.back.pojo.User;
import com.wechat.back.pojo.comment.PoiLike;
import com.wechat.back.pojo.tools.PageBean;
import com.wechat.back.pojo.Place;
import com.wechat.back.service.PlaceService;
import com.wechat.back.utils.ChineseStopWordRemover;
import com.wechat.back.utils.TFIDFUtil;
import com.wechat.back.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class PlaceServiceImpl implements PlaceService {

    @Autowired
    private PlaceMapper placeMapper;

    @Autowired
    private LikeMapper likeMapper;

    @Autowired
    private UserMapper userMapper;
    @Override
    public Place findById(Integer poiId) {
        Place place = placeMapper.findById(poiId);
        return place;
    }

    @Override
    public PageBean<Place> list(Integer pageNum, Integer pageSize, String poiName, String poiType) {
        //1.创建PageBean对象
        PageBean<Place> pl = new PageBean<>();
        //2.开启分页查询 PageHelper
        PageHelper.startPage(pageNum,pageSize);
        //调用mapper
        List<Place> places = placeMapper.list(poiName,poiType);
        Page<Place> p = (Page<Place>) places;

        pl.setTotal(p.getTotal());
        pl.setItems(p.getResult());

        return pl;
    }

    //推荐(基于评论评分)
    @Override
    public List<Place> listByCommentRecommend(String poiType) {
        return placeMapper.listByCommentRecommend(poiType);
    }

    //推荐(基于内容相似度)
    @Override
    public List<Place> listByContentRecommend(Integer limit, String poiType) {
        Integer SpoiId = null;
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");
        List<PoiLike> poiLikes = likeMapper.listPoiLike(SpoiId,userId);
        List<Integer> poiIds = poiLikes.stream()
                .map(PoiLike::getPoiId)
                .toList();

        Integer poiId = getRandomPoiId(poiIds);
        //如果poiId为空，则固定poiId为1
        List<Place> allPlaces = placeMapper.listAllByType(poiType);
        Place targetPlace = allPlaces.stream()
                .filter(p -> p.getPoiId().equals(poiId))
                .findFirst()
                .orElse(null);

        if (targetPlace == null) {
            return Collections.emptyList();
        }

        // 计算相似度
        Map<Place, Double> similarityMap = new HashMap<>();
        for (Place place : allPlaces) {
            if (!place.getPoiId().equals(poiId)) {
                double similarity = calculateCosineSimilarity(targetPlace, place);
                similarityMap.put(place, similarity);
            }
        }

        // 按相似度排序并返回前N个
        return similarityMap.entrySet().stream()
                .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))
                .limit(limit)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }
    private static Integer getRandomPoiId(List<Integer> poiIds) {
        if (poiIds == null || poiIds.isEmpty()) {
            return null; // 如果列表为空，返回null
        }
        Random random = new Random();
        int randomIndex = random.nextInt(poiIds.size());
        return poiIds.get(randomIndex);
    }

    private double calculateCosineSimilarity(Place place1, Place place2) {
        // 提取标签集合并进行预处理（去除空格、统一小写）
        Set<String> tags1 = preprocessTags(place1.getTagList1());
        Set<String> tags2 = preprocessTags(place2.getTagList1());

        // 计算点积（交集大小）
        long dotProduct = tags1.stream().filter(tags2::contains).count();

        // 计算模长
        double magnitude1 = Math.sqrt(tags1.size());
        double magnitude2 = Math.sqrt(tags2.size());

        // 避免除以零
        if (magnitude1 == 0 || magnitude2 == 0) {
            return 0.0;
        }

        // 计算余弦相似度
        return dotProduct / (magnitude1 * magnitude2);
    }

    private Set<String> preprocessTags(String tagList) {
        return Arrays.stream(tagList.split(","))
                .map(String::trim) // 去除多余空格
                .map(String::toLowerCase) // 统一小写
                .filter(tag -> !tag.isEmpty()) // 过滤空标签
                .collect(Collectors.toSet());
    }


    //推荐(基于热度)
    @Override
    public List<Place> listByHotRecommend(Integer limit,String poiName, String poiType) {
        List<Place> allPlaces  = placeMapper.list(poiName,poiType);
        return allPlaces.stream()
                .sorted((p1, p2) -> Double.compare(calculateHotness(p2), calculateHotness(p1)))
                .limit(limit)
                .collect(Collectors.toList());
    }

    private double calculateHotness(Place place) {
        // 如果commentScore为null，使用默认值0.0
        double score = (place.getCommentScore() != null) ? place.getCommentScore() : 0.0;
        // 如果commentCount为null，使用默认值0
        int count = (place.getCommentCount() != null) ? place.getCommentCount() : 0;
        return score * Math.log(count + 1);
    }

    //推荐（基于用户爱好）
    @Override
    public List<Place> listByUserHobbyRecommend(String poiType) {
//        String poiName = null;
        List<Place> allPlaces = placeMapper.list(null,poiType);
        Map<String,Object> map = ThreadLocalUtil.get();
        Integer userId = (Integer) map.get("id");
        User users = userMapper.findById(userId);
        String Hobby  = users.getHobby();
        //处理用户爱好
        ChineseStopWordRemover defaultRemover = new ChineseStopWordRemover();
        String userHobby = defaultRemover.removeStopWords(Hobby);
        System.out.println("userHobby"+userHobby);

        // 将用户爱好和地点标签转换为文档列表
        List<String> documents = new ArrayList<>();
        documents.add(userHobby);
        for (Place place : allPlaces) {
            documents.add(place.getTagList1());
        }

        // 初始化TF-IDF工具
        TFIDFUtil tfidfUtil = new TFIDFUtil(documents);

        // 计算用户爱好和每个地点标签的TF-IDF向量
        Map<String, Double> userHobbyVector = tfidfUtil.getTFIDFVector(userHobby);

        // 计算相似度
        Map<Place, Double> similarityScores = new HashMap<>();
        for (Place place : allPlaces) {
            Map<String, Double> placeVector = tfidfUtil.getTFIDFVector(place.getTagList1());
            double similarity = tfidfUtil.cosineSimilarity(userHobbyVector, placeVector);
            similarityScores.put(place, similarity);
        }

        // 按相似度排序并限制推荐数量为50
        List<Place> recommendedPlaces = similarityScores.entrySet().stream()
                .sorted(Map.Entry.<Place, Double>comparingByValue().reversed()) // 按相似度降序排序
                .map(Map.Entry::getKey) // 提取地点对象
                .limit(50) // 限制推荐数量为10
                .collect(Collectors.toList()); // 收集结果
        return recommendedPlaces;
    }

    @Override
    public void add(Place place) {
        placeMapper.add(place);

    }

    @Override
    public void update(Place place) {
        placeMapper.update(place);
    }

    @Override
    public void deleteById(Integer poiId) {
        placeMapper.deleteById(poiId);
    }
}
